package org.longteng.security.handle;

import org.longteng.core.base.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.client.RestClientException;

import javax.security.auth.message.AuthException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 * 200：成功；
 * 401：token验证失败；
 * 402：用户验证失败；
 * 500：服务器异常；
 * 5000：输入参数不完整
 * @author hymn.com
 * @date 2022/12/09 10:00:00
 */
@Slf4j
@ControllerAdvice(basePackages={"com.huawei.elinkbus.csgvpp.api"})
@Component
public class GlobalApiErrorHandler {


    /**
    * 处理@Validated参数校验失败异常
     * @param exception 异常类
     * @return 响应
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)  // spring参数验证400错误
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public CommonResult<Void> exceptionHandler(MethodArgumentNotValidException exception) {
        log.info("处理@Validated参数校验失败异常.");

        BindingResult result = exception.getBindingResult();
        StringBuilder stringBuilder = new StringBuilder();
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            if (errors != null) {
                errors.forEach(p -> {
                    FieldError fieldError = (FieldError) p;
                    log.warn("Bad Request Parameters: dto entity [{}],field [{}],message [{}]", fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
                    stringBuilder.append(fieldError.getDefaultMessage());
                });
            }
        }
        return CommonResult.toBuilder(5000)
                .message(stringBuilder.toString())
                .build();
    }
    /**
     * 全局处理所有使用了@validation校验参数的controller
     * @param e 捕获到validation抛出异常
     * @return 返回参数中所有的校验错误，以,分隔不用的错误信息
     */
    @ResponseBody
    @ExceptionHandler(BindException.class)
    public CommonResult<Void> exceptionHandler(BindException e) {
        String errors=e.getBindingResult().getAllErrors().stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.joining(","));
        log.error("Request params error,caught by global exception handler,{}",errors);
        return CommonResult.toBuilder(5000)
                .message(errors)
                .build();
    }

    /**
     * 传入参数json转换错误
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public CommonResult<Void> exceptionHandler(HttpMessageNotReadableException e) {
        // String errors= e.getLocalizedMessage();
        log.error("传入参数json转换错误,caught by global converter exception handler.",e);
        return CommonResult.toBuilder(5000)
                .message("传入参数json格式错误" +
                        "")
                .build();
    }

    /**
     * token安全验证错误
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(AuthException.class)
    public CommonResult<Void> exceptionHandler(AuthException e) {
        String errors=e.getLocalizedMessage();
        log.error("token安全验证错误，exception handler,{}",errors);
        return CommonResult.toBuilder(401)
                .message("token 验证失败")
                .build();
    }

    /**
     * 调用neteco接口错误
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(RestClientException.class)
    public CommonResult<Void> exceptionHandler(RestClientException e) {
        String errors=e.getLocalizedMessage();
        log.error("调用neteco接口异常，可能neteco不通，exception handler,{}",errors);
        return CommonResult.toBuilder(500)
                .message("服务器异常,可能南向接口不通")
                .build();
    }

    /**
     * 全部局异常处理
     * @param e
     * @return
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public CommonResult<Void> exceptionHandler(Exception e) {
        String errors=e.getLocalizedMessage();
        log.error("服务器异常, 服务发生错误，exception handler,{}", errors, e);
        return CommonResult.toBuilder(500)
                .message("服务器异常")
                .build();
    }
}
